package com.example.demo.aop;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import com.example.demo.annotation.MyAnnotion;

@Aspect
@Component
public class TestAspect {
	 /**
	  * 定义切入点：对要拦截的方法进行定义与限制，如包、类
     *
     * 1、execution(public * *(..)) 任意的公共方法
     * 2、execution(* set*(..)) 以set开头的所有的方法
     * 3、execution(* com.lingyejun.annotation.LoggerApply.*(..))com.lingyejun.annotation.LoggerApply这个类里的所有的方法
     * 4、execution(* com.lingyejun.annotation.*.*(..))com.lingyejun.annotation包下的所有的类的所有的方法
     * 5、execution(* com.lingyejun.annotation..*.*(..))com.lingyejun.annotation包及子包下所有的类的所有的方法
     * 6、execution(* com.lingyejun.annotation..*.*(String,?,Long)) com.lingyejun.annotation包及子包下所有的类的有三个参数，第一个参数为String类型，第二个参数为任意类型，第三个参数为Long类型的方法
     * 7、execution(@annotation(com.lingyejun.annotation.Lingyejun))
     * 8、executeion(public * com.example.demo.system.web.*.*(..)) && @annotation(com.example.demo.annotation.MyAnnotion))表示在system的web包下所有加了MyAnnotion注解的方法都会触发切脉你
     */
	@Pointcut("@annotation(com.example.demo.annotation.MyAnnotion)")//表示只要加了MyAnnotion注解的方法都会触发这个切面
	public void addAdvice() {
		
	}
	
	/**
	 * @创建时间 2020年8月29日
	 * @创建人 许子文
	 * @功能描述: 在方法执行之前执行此方法
	 */
	@Before("addAdvice()")
	public void begin() {
		
	}
	
	/**
	 * @创建时间 2020年8月29日
	 * @创建人 许子文
	 * @功能描述: 在方法执行结束以后执行此方法，如果方法抛出异常则不执行
	 */
	@AfterReturning("addAdvice()")
	public void afterReturn() {
		
	}
	
	/**
	 * @创建时间 2020年8月29日
	 * @创建人 许子文
	 * @功能描述: 无论方法是否抛出异常，都会在方法结束时调用
	 */
	@After("addAdvice()")
	public void after() {
		
	}
	
	/**
	 * @创建时间 2020年8月29日
	 * @创建人 许子文
	 * @功能描述: 目标方法抛出异常时执行的方法
	 */
	@AfterThrowing("addAdvice()")
	public void afterThrowException() {
		
	}
	
	/**
	 * @param pjp
	 * @return
	 * @创建时间 2020年8月29日
	 * @创建人 许子文
	 * @功能描述: 环绕通知：灵活自由的在目标方法中切入代码
	 */
	@Around("addAdvice()")
	public Object Interceptor(ProceedingJoinPoint pjp) {
		Object[] args = pjp.getArgs();
		
		for (int i = 0; i < args.length; i++) {
			System.out.println("参数值>>>"+args[i]);
		}
		
		Object result = null;
		
		
		Class<?> aClass = pjp.getTarget().getClass();//获得所在切点的该类的class对象
		
		String methodName = pjp.getSignature().getName();//获得该切点所在的方法的名称
		
		Class<?>[] parameterTypes = ((MethodSignature)pjp.getSignature()).getParameterTypes();//拿到方法对应的参数类型
		
		try {
			Method method = aClass.getMethod(methodName, parameterTypes);//获取该方法对象
			
			MyAnnotion annotion = method.getAnnotation(MyAnnotion.class);//拿到对象上的注解
			
			String value = annotion.value();
			
			System.out.println(".............被切面拦截了,注解的值>>>"+value);
		} catch (NoSuchMethodException | SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		try {
			result = pjp.proceed();//继续执行原来的方法并拿到出参
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return result;
	}
}
